/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
(function(factory) {
"use strict";
if (typeof module === "object" && module.exports) {
module.exports = factory();
} else {
var g = window.Granite = window.Granite || {};
g.Sling = factory();
}
}(function() {
"use strict";
/**
* A helper class providing a set of Sling-related utilities.
* @static
* @singleton
* @class Granite.Sling
* @deprecated Using the constants is no longer needed and actually is not a best practice as it is not RESTful,
* where the server should drive the client via hypermedia and the client should not make any
* assumption about the URL.
*/
return {
/**
* The selector for infinite hierarchy depth when retrieving repository content.
* @static
* @final
* @type String
*/
SELECTOR_INFINITY: ".infinity",
/**
* The parameter name for the used character set.
* @static
* @final
* @type String
*/
CHARSET: "_charset_",
/**
* The parameter name for the status.
* @static
* @final
* @type String
*/
STATUS: ":status",
/**
* The parameter value for the status type "browser".
* @static
* @final
* @type String
*/
STATUS_BROWSER: "browser",
/**
* The parameter name for the operation.
* @static
* @final
* @type String
*/
OPERATION: ":operation",
/**
* The parameter value for the delete operation.
* @static
* @final
* @type String
*/
OPERATION_DELETE: "delete",
/**
* The parameter value for the move operation.
* @static
* @final
* @type String
*/
OPERATION_MOVE: "move",
/**
* The parameter name suffix for deleting.
* @static
* @final
* @type String
*/
DELETE_SUFFIX: "@Delete",
/**
* The parameter name suffix for setting a type hint.
* @static
* @final
* @type String
*/
TYPEHINT_SUFFIX: "@TypeHint",
/**
* The parameter name suffix for copying.
* @static
* @final
* @type String
*/
COPY_SUFFIX: "@CopyFrom",
/**
* The parameter name suffix for moving.
* @static
* @final
* @type String
*/
MOVE_SUFFIX: "@MoveFrom",
/**
* The parameter name for the ordering.
* @static
* @final
* @type String
*/
ORDER: ":order",
/**
* The parameter name for the replace flag.
* @static
* @final
* @type String
*/
REPLACE: ":replace",
/**
* The parameter name for the destination flag.
* @static
* @final
* @type String
*/
DESTINATION: ":dest",
/**
* The parameter name for the save parameter prefix.
* @static
* @final
* @type String
*/
SAVE_PARAM_PREFIX: ":saveParamPrefix",
/**
* The parameter name for input fields that should be ignored by Sling.
* @static
* @final
* @type String
*/
IGNORE_PARAM: ":ignore",
/**
* The parameter name for login requests.
* @static
* @final
* @type String
*/
REQUEST_LOGIN_PARAM: "sling:authRequestLogin",
/**
* The login URL.
* @static
* @final
* @type String
*/
LOGIN_URL: "/system/sling/login.html",
/**
* The logout URL.
* @static
* @final
* @type String
*/
LOGOUT_URL: "/system/sling/logout.html"
};
}));
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
(function(factory) {
"use strict";
if (typeof module === "object" && module.exports) {
module.exports = factory();
} else {
var g = window.Granite = window.Granite || {};
g.Util = factory();
}
}(function() {
"use strict";
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray#Polyfill
var isArray = function(arg) {
return Object.prototype.toString.call(arg) === "[object Array]";
};
/**
* A helper class providing a set of general utilities.
* @static
* @singleton
* @class Granite.Util
*/
return {
/**
* Replaces occurrences of {n} in the specified text with the texts from the snippets.
*
* @example
* var text = Granite.Util.patchText("{0} has signed in.", "Jack");
* // text = "Jack has signed in."
* var text2 = Granite.Util.patchText("{0} {1} has signed in from {2}.", ["Jack", "McFarland", "x.x.x.x"]);
* // text2 = "Jack McFarland has signed in from x.x.x.x."
*
* @param {String} text The text.
* @param {String|String[]} snippets The text(s) replacing {n}.
* @returns {String} The patched text.
*/
patchText: function(text, snippets) {
if (snippets) {
if (!isArray(snippets)) {
text = text.replace("{0}", snippets);
} else {
for (var i = 0; i < snippets.length; i++) {
text = text.replace(("{" + i + "}"), snippets[i]);
}
}
}
return text;
},
/**
* Returns the top most accessible window.
* Check {@link .setIFrameMode} to avoid security exception message on WebKit browsers
* if this method is called in an iFrame included in a window from different domain.
*
* @returns {Window} The top window.
*/
getTopWindow: function() {
var win = window;
if (this.iFrameTopWindow) {
return this.iFrameTopWindow;
}
try {
// try to access parent
// win.parent.location.href throws an exception if not authorized (e.g. different location in a portlet)
while (win.parent && win !== win.parent && win.parent.location.href) {
win = win.parent;
}
} catch (error) {
// ignored
}
return win;
},
/**
* Allows to define if Granite.Util is running in an iFrame and parent window is in another domain
* (and optionally define what would be the top window in that case.
* This is necessary to use {@link .getTopWindow} in a iFrame on WebKit based browsers because
* {@link .getTopWindow} iterates on parent windows to find the top one which triggers a security exception
* if one parent window is in a different domain. Exception cannot be caught but is not breaking the JS
* execution.
*
* @param {Window} [topWindow=window] The iFrame top window. Must be running on the same host to avoid
* security exception.
*/
setIFrameMode: function(topWindow) {
this.iFrameTopWindow = topWindow || window;
},
/**
* Applies default properties if non-existent into the base object.
* Child objects are merged recursively.
* REMARK:
* - objects are recursively merged
* - simple type object properties are copied over the base
* - arrays are cloned and override the base (no value merging)
*
* @param {Object} base The object.
* @param {...Object} pass The objects to be copied onto the base.
* @returns {Object} The base object with defaults.
*/
applyDefaults: function() {
var override;
var base = arguments[0] || {};
for (var i = 1; i < arguments.length; i++) {
override = arguments[i];
for (var name in override) {
var value = override[name];
if (override.hasOwnProperty(name) && value !== undefined) {
if (value !== null && typeof value === "object" && !(value instanceof Array)) {
// nested object
base[name] = this.applyDefaults(base[name], value);
} else if (value instanceof Array) {
// override array
base[name] = value.slice(0);
} else {
// simple type
base[name] = value;
}
}
}
}
return base;
},
/**
* Returns the keycode from the given event.
* It is a normalized value over variation of browsers' inconsistencies.
*
* @param {UIEvent} event The event.
* @returns {Number} The keycode.
*/
getKeyCode: function(event) {
return event.keyCode ? event.keyCode : event.which;
}
};
}));
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/* global CQURLInfo:false, G_XHR_HOOK:false */
/* eslint strict: 0 */
(function(factory) {
"use strict";
if (typeof module === "object" && module.exports) {
module.exports = factory(require("@granite/util"), require("jquery"));
} else {
window.Granite.HTTP = factory(Granite.Util, jQuery);
}
}(function(util, $) {
/**
* A helper class providing a set of HTTP-related utilities.
* @static
* @singleton
* @class Granite.HTTP
*/
return (function() {
/**
* The context path used on the server.
* May only be set by {@link #detectContextPath}.
* @type String
*/
var contextPath = null;
/**
* The regular expression to detect the context path used
* on the server using the URL of this script.
* @readonly
* @type RegExp
*/
// eslint-disable-next-line max-len
var SCRIPT_URL_REGEXP = /^(?:http|https):\/\/[^/]+(\/.*)\/(?:etc\.clientlibs|etc(\/.*)*\/clientlibs|libs(\/.*)*\/clientlibs|apps(\/.*)*\/clientlibs|etc\/designs).*\.js(\?.*)?$/;
/**
* The regular expression to match `#` and other non-ASCII characters in a URI.
* @readonly
* @type RegExp
*/
var ENCODE_PATH_REGEXP = /[^\w-.~%:/?[\]@!$&'()*+,;=]/;
/**
* The regular expression to parse URI.
* @readonly
* @type RegExp
* @see https://tools.ietf.org/html/rfc3986#appendix-B
*/
var URI_REGEXP = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
/**
* Indicates after a session timeout if a refresh has already been triggered
* in order to avoid multiple alerts.
* @type String
*/
var loginRedirected = false;
var self = {};
/**
* Returns the scheme and authority (userinfo, host, port) components of the given URI;
* or an empty string if the URI does not have the components.
*
* This method assumes the URI is valid.
*
* e.g. `scheme://userinfo@host:80/path?query#fragment` -> `scheme://userinfo@host:80`
*
* @param {String} uri The URI
* @returns {String} The scheme and authority components
*/
self.getSchemeAndAuthority = function(uri) {
if (!uri) {
return "";
}
var result = URI_REGEXP.exec(uri);
if (result === null) {
return "";
}
return [ result[1], result[3] ].join("");
};
/**
* Returns the context path used on the server.
*
* @returns {String} The context path
*/
self.getContextPath = function() {
// Keep cache of calculated path.
if (contextPath === null) {
contextPath = self.detectContextPath();
}
return contextPath;
};
/**
* Detects the context path used on the server.
*
* @returns {String} The context path
* @private
*/
self.detectContextPath = function() {
try {
if (window.CQURLInfo) {
contextPath = CQURLInfo.contextPath || "";
} else {
var scripts = document.getElementsByTagName("script");
for (var i = 0; i < scripts.length; i++) {
var result = SCRIPT_URL_REGEXP.exec(scripts[i].src);
if (result) {
contextPath = result[1];
return contextPath;
}
}
contextPath = "";
}
} catch (e) {
// ignored
}
return contextPath;
};
/**
* Makes sure the specified relative URL starts with the context path
* used on the server. If an absolute URL is passed, it will be returned
* as-is.
*
* @param {String} url The URL
* @returns {String} The externalized URL
*/
self.externalize = function(url) {
try {
if (url.indexOf("/") === 0 && self.getContextPath() && url.indexOf(self.getContextPath() + "/") !== 0) {
url = self.getContextPath() + url;
}
} catch (e) {
// ignored
}
return url;
};
/**
* Removes scheme, authority and context path from the specified
* absolute URL if it has the same scheme and authority as the
* specified document (or the current one). If a relative URL is passed,
* the context path will be stripped if present.
*
* @param {String} url The URL
* @param {String} doc (optional) The document
* @returns {String} The internalized URL
*/
self.internalize = function(url, doc) {
if (url.charAt(0) === "/") {
if (contextPath === url) {
return "";
} else if (contextPath && url.indexOf(contextPath + "/") === 0) {
return url.substring(contextPath.length);
} else {
return url;
}
}
if (!doc) {
doc = document;
}
var docHost = self.getSchemeAndAuthority(doc.location.href);
var urlHost = self.getSchemeAndAuthority(url);
if (docHost === urlHost) {
return url.substring(urlHost.length + (contextPath ? contextPath.length : 0));
} else {
return url;
}
};
/**
* Removes all parts but the path from the specified URL.
*
Examples:
/x/y.sel.html?param=abc => /x/y
*
http://www.day.com/foo/bar.html => /foo/bar
*
* @param {String} url The URL, may be empty. If empty window.location.href is taken.
* @returns {String} The path
*/
self.getPath = function(url) {
if (!url) {
if (window.CQURLInfo && CQURLInfo.requestPath) {
return CQURLInfo.requestPath;
} else {
url = window.location.pathname;
}
} else {
url = self.removeParameters(url);
url = self.removeAnchor(url);
}
url = self.internalize(url);
var i = url.indexOf(".", url.lastIndexOf("/"));
if (i !== -1) {
url = url.substring(0, i);
}
return url;
};
/**
* Removes the fragment component from the given URI.
*
* This method assumes the URI is valid.
*
* e.g. `scheme://userinfo@host:80/path?query#fragment` -> `scheme://userinfo@host:80/path?query`
*
* @param {String} uri The URI
* @returns {String} The URI without fragment component
*/
self.removeAnchor = function(uri) {
var fragmentIndex = uri.indexOf("#");
if (fragmentIndex >= 0) {
return uri.substring(0, fragmentIndex);
} else {
return uri;
}
};
/**
* Removes the query component and its subsequent fragment component from the given URI.
* i.e. When query component exists, the subsequent fragment component is also removed.
* However, when query component doesn't exist, fragment component is not removed.
*
* The assumption here is that the usages of `#` before the `?` are intended as part of the path component
* that need to be encoded separately.
* This assumption is made because `c.d.cq.commons.jcr.JcrUtil#isValidName` allows `#`.
*
* e.g. `scheme://userinfo@host:80/path#with#hash?query#fragment` -> `scheme://userinfo@host:80/path#with#hash`
*
* @param {String} uri The URL
* @returns {String} The URI without the query component and its subsequent fragment component
*/
self.removeParameters = function(uri) {
var queryIndex = uri.indexOf("?");
if (queryIndex >= 0) {
return uri.substring(0, queryIndex);
} else {
return uri;
}
};
/**
* Encodes the path component of the given URI if it is not already encoded.
* See {@link #encodePath} for the details of the encoding.
*
* e.g. `scheme://userinfo@host:80/path#with#hash?query#fragment`
* -> `scheme://userinfo@host:80/path%23with%23hash?query#fragment`
*
* @param {String} uri The URI to encode
* @returns {String} The encoded URI
*/
self.encodePathOfURI = function(uri) {
var DELIMS = [ "?", "#" ];
var parts = [ uri ];
var delim;
for (var i = 0, ln = DELIMS.length; i < ln; i++) {
delim = DELIMS[i];
if (uri.indexOf(delim) >= 0) {
parts = uri.split(delim);
break;
}
}
if (ENCODE_PATH_REGEXP.test(parts[0])) {
parts[0] = self.encodePath(parts[0]);
}
return parts.join(delim);
};
/**
* Encodes the given URI using `encodeURI`.
*
* This method is used to encode URI components from the scheme component up to the path component (inclusive).
* Therefore, `?` and `#` are also encoded in addition.
*
* However `[` and `]` are not encoded.
* The assumption here is that the usages of `[` and `]` are only at the host component (for IPv6),
* not at the path component.
* This assumption is made because `c.d.cq.commons.jcr.JcrUtil#isValidName` disallows `[` and `]`.
*
* Examples
*
* * `scheme://userinfo@host:80/path?query#fragment` -> `scheme://userinfo@host:80/path%3Fquery%23fragment`
* * `http://[2001:db8:85a3:8d3:1319:8a2e:370:7348]/` -> `http://[2001:db8:85a3:8d3:1319:8a2e:370:7348]/`
*
* @param {String} uri The URI to encode
* @returns {String} The encoded URI
*/
self.encodePath = function(uri) {
uri = encodeURI(uri);
// Decode back `%5B` and `%5D`.
// The `[` and `]` are not valid characters at the path component and need to be encoded,
// which `encodeURI` does correctly.
// However as mentioned in the doc, they are assumed to be used for authority component only.
uri = uri.replace(/%5B/g, "[").replace(/%5D/g, "]");
uri = uri.replace(/\?/g, "%3F");
uri = uri.replace(/#/g, "%23");
return uri;
};
/**
* Handles login redirection if needed.
*/
self.handleLoginRedirect = function() {
if (!loginRedirected) {
loginRedirected = true;
alert(Granite.I18n.get("Your request could not be completed because you have been signed out."));
var l = util.getTopWindow().document.location;
l.href = self.externalize("/") + "?resource=" + encodeURIComponent(l.pathname + l.search + l.hash);
}
};
/**
* Gets the XHR hooked URL if called in a portlet context
*
* @param {String} url The URL to get
* @param {String} method The method to use to retrieve the XHR hooked URL
* @param {Object} params The parameters
* @returns {String} The XHR hooked URL if available, the provided URL otherwise
*/
self.getXhrHook = function(url, method, params) {
method = method || "GET";
if (window.G_XHR_HOOK && typeof G_XHR_HOOK === "function") {
var p = {
"url": url,
"method": method
};
if (params) {
p["params"] = params;
}
return G_XHR_HOOK(p);
}
return null;
};
/**
* Evaluates and returns the body of the specified response object.
* Alternatively, a URL can be specified, in which case it will be
* requested using a synchronous {@link #get} in order to acquire
* the response object.
*
* @param {Object|String} response The response object or URL
* @returns {Object} The evaluated response body
* @since 5.3
*/
self.eval = function(response) {
if (typeof response !== "object") {
response = $.ajax({
url: response,
type: "get",
async: false
});
}
try {
// support responseText for backward compatibility (pre 5.3)
var text = response.body ? response.body : response.responseText;
return JSON.parse(text);
} catch (e) {
// ignored
}
return null;
};
return self;
}());
}));
/*
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2012 Adobe
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe.
*/
(function(factory) {
"use strict";
if (typeof module === "object" && module.exports) {
module.exports = factory(require("@granite/http"));
} else {
window.Granite.I18n = factory(window.Granite.HTTP);
}
}(function(HTTP) {
"use strict";
/**
* A helper class providing a set of utilities related to internationalization (i18n).
*
*
The locale is read based on the following priorities:
*document.documentElement.langGranite.I18n.LOCALE_DEFAULTThe dictionary URL is read based on the following priorities:
*urlPrefixurlSuffix)data-i18n-dictionary-src attribute at <html> element,
* which has the type of URI Template stringurlPrefix and urlSuffixIt expects the variable named locale,
* which will be fetched from the locale (based on priorities above).
* E.g. <html lang="en" data-i18n-dictionary-src="/libs/cq/i18n/dict.{+locale}.json">.
{
"locale": "fr",
"urlPrefix": "/apps/i18n/dict.",
"urlSuffix": ".json"
}
*
* @param {Object} config The config
*/
self.init = function(config) {
config = config || {};
this.setLocale(config.locale);
this.setUrlPrefix(config.urlPrefix);
this.setUrlSuffix(config.urlSuffix);
};
/**
* Sets the current locale.
*
* @param {String|Function} locale The locale or a function that returns the locale as a string
*/
self.setLocale = function(locale) {
if (!locale) {
return;
}
manualLocale = locale;
};
/**
* Returns the current locale based on the priorities.
*
* @returns {String} The locale
*/
self.getLocale = function() {
if (typeof manualLocale === "function") {
// execute function first time only and store result in currentLocale
manualLocale = manualLocale();
}
return manualLocale || document.documentElement.lang || self.LOCALE_DEFAULT;
};
/**
* Sets the prefix for the URL used to request dictionaries from
* the server. The locale and URL suffix will be appended.
*
* @param {String} prefix The URL prefix
*/
self.setUrlPrefix = function(prefix) {
if (!prefix) {
return;
}
urlPrefix = prefix;
manualDictionary = true;
};
/**
* Sets the suffix for the URL used to request dictionaries from
* the server. It will be appended to the URL prefix and locale.
*
* @param {String} suffix The URL suffix
*/
self.setUrlSuffix = function(suffix) {
if (!suffix) {
return;
}
urlSuffix = suffix;
manualDictionary = true;
};
/**
* Returns the dictionary for the specified locale. This method
* will request the dictionary using the URL prefix, the locale,
* and the URL suffix. If no locale is specified, the current
* locale is used.
*
* @param {String} locale (optional) The locale
* @returns {Object} The dictionary
*/
self.getDictionary = function(locale) {
locale = locale || self.getLocale();
if (!dicts[locale]) {
pseudoTranslations = locale.indexOf(self.PSEUDO_LANGUAGE) === 0;
try {
var xhr = new XMLHttpRequest();
xhr.open("GET", HTTP.externalize(getDictionaryUrl(locale)), false);
xhr.send();
dicts[locale] = JSON.parse(xhr.responseText);
} catch (e) {
// ignored
}
if (!dicts[locale]) {
dicts[locale] = {};
}
}
return dicts[locale];
};
/**
* Translates the specified text into the current language.
*
* @param {String} text The text to translate
* @param {String[]} snippets The snippets replacing {n} (optional)
* @param {String} note A hint for translators (optional)
* @returns {String} The translated text
*/
self.get = function(text, snippets, note) {
var dict;
var newText;
var lookupText;
dict = self.getDictionary();
// note that pseudoTranslations is initialized in the getDictionary() call above
lookupText = pseudoTranslations ? self.PSEUDO_PATTERN_KEY
: note ? text + " ((" + note + "))"
: text;
if (dict) {
newText = dict[lookupText];
}
if (!newText) {
newText = text;
}
if (pseudoTranslations) {
newText = newText.replace("{string}", text).replace("{comment}", note ? note : "");
}
return patchText(newText, snippets);
};
/**
* Translates the specified text into the current language. Use this
* method to translate String variables, e.g. data from the server.
*
* @param {String} text The text to translate
* @param {String} note A hint for translators (optional)
* @returns {String} The translated text
*/
self.getVar = function(text, note) {
if (!text) {
return null;
}
return self.get(text, null, note);
};
/**
* Returns the available languages, including a "title" property with a display name:
* for instance "German" for "de" or "German (Switzerland)" for "de_ch".
*
* @returns {Object} An object with language codes as keys and an object with "title",
* "language", "country" and "defaultCountry" members.
*/
self.getLanguages = function() {
if (!languages) {
try {
// use overlay servlet so customers can define /apps/wcm/core/resources/languages
// TODO: broken!!!
var url = HTTP.externalize("/libs/wcm/core/resources/languages.overlay.infinity.json");
var xhr = new XMLHttpRequest();
xhr.open("GET", url, false);
xhr.send();
var json = JSON.parse(xhr.responseText);
Object.keys(json).forEach(function(prop) {
var lang = json[prop];
if (lang.language) {
lang.title = self.getVar(lang.language);
}
if (lang.title && lang.country && lang.country !== "*") {
lang.title += " (" + self.getVar(lang.country) + ")";
}
});
languages = json;
} catch (e) {
languages = {};
}
}
return languages;
};
/**
* Parses a language code string such as "de_CH" and returns an object with
* language and country extracted. The delimiter can be "_" or "-".
*
* @param {String} langCode a language code such as "de" or "de_CH" or "de-ch"
* @returns {Object} an object with "code" ("de_CH"), "language" ("de") and "country" ("CH")
* (or null if langCode was null)
*/
self.parseLocale = function(langCode) {
if (!langCode) {
return null;
}
var pos = langCode.indexOf("_");
if (pos < 0) {
pos = langCode.indexOf("-");
}
var language;
var country;
if (pos < 0) {
language = langCode;
country = null;
} else {
language = langCode.substring(0, pos);
country = langCode.substring(pos + 1);
}
return {
code: langCode,
language: language,
country: country
};
};
return self;
}());
}));
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
(function(factory) {
"use strict";
if (typeof module === "object" && module.exports) {
module.exports = factory();
} else {
var g = window.Granite = window.Granite || {};
g.TouchIndicator = factory();
}
}(function() {
"use strict";
function createIndicator() {
var el = document.createElement("div");
el.style.visibility = "hidden";
// fixed would be better, but flickers on ipad while scrolling
el.style.position = "absolute";
el.style.width = "30px";
el.style.height = "30px";
el.style.borderRadius = "20px";
el.style.border = "5px solid orange";
el.style.userSelect = "none";
el.style.opacity = "0.5";
el.style.zIndex = "2000";
el.style.pointerEvents = "none";
return el;
}
var used = {};
var unused = [];
/**
* Implements the "Adobe Dynamic Touch Indicator" that tracks touch events and displays a visual indicator for
* screen sharing and presentation purposes.
*
* To enable it, call Granite.TouchIndicator.init() e.g. on document ready:
*
* Granite.$(document).ready(function() {
* Granite.TouchIndicator.init();
* });
*
*
* AdobePatentID="2631US01"
*/
return {
debugWithMouse: false,
init: function() {
var self = this;
var update = function(e) {
self.update(e.touches);
return true;
};
document.addEventListener("touchstart", update);
document.addEventListener("touchmove", update);
document.addEventListener("touchend", update);
if (this.debugWithMouse) {
document.addEventListener("mousemove", function(e) {
e.identifer = "fake";
self.update([ e ]);
return true;
});
}
},
update: function(touches) {
// go over all touch events present in the array
var retained = {};
for (var i = 0; i < touches.length; i++) {
var touch = touches[i];
var id = touch.identifier;
// check if we already have a indicator with the correct id
var indicator = used[id];
if (!indicator) {
// if not, check if we have an unused one
indicator = unused.pop();
// if not, create a new one and append it to the dom
if (!indicator) {
indicator = createIndicator();
document.body.appendChild(indicator);
}
}
retained[id] = indicator;
indicator.style.left = (touch.pageX - 20) + "px";
indicator.style.top = (touch.pageY - 20) + "px";
indicator.style.visibility = "visible";
}
// now hide all unused ones and stuff them in the unused array
for (id in used) {
if (used.hasOwnProperty(id) && !retained[id]) {
indicator = used[id];
indicator.style.visibility = "hidden";
unused.push(indicator);
}
}
used = retained;
}
};
}));
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
(function(factory) {
"use strict";
if (typeof module === "object" && module.exports) {
module.exports = factory();
} else {
var g = window.Granite = window.Granite || {};
g.OptOutUtil = factory();
}
}(function($) {
"use strict";
function trim(s) {
if (String.prototype.trim) {
return s.trim();
}
return s.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
}
/**
* A library to determine whether any opt-out cookie is set and whether a given cookie name is white-listed.
*
* The opt-out and white-list cookie names are determined by a server-side configuration
* (com.adobe.granite.security.commons.OptOutService) and provided to this tool by an optionally
* included component (/libs/granite/security/components/optout) which provides a global JSON object
* named GraniteOptOutConfig.
*
* @static
* @class Granite.OptOutUtil
*/
return (function() {
var self = {};
/**
* The names of cookies the presence of which indicates the user has opted out.
* @type String[]
*/
var optOutCookieNames = [];
/**
* The names of cookies which may still be set in spite of the user having opted out.
* @type String[]
*/
var whitelistedCookieNames = [];
/**
* Initializes this tool with an opt-out configuration.
*
* The following options are supported:
* true if an opt-cookie was found in the browser's cookies;
* false otherwise.
*/
self.isOptedOut = function() {
var browserCookies = document.cookie.split(";");
for (var i = 0; i < browserCookies.length; i++) {
var cookie = browserCookies[i];
var cookieName = trim(cookie.split("=")[0]);
if (self.getCookieNames().indexOf(cookieName) >= 0) {
return true;
}
}
return false;
};
/**
* Determines whether the given cookieName may be used to set a cookie.
* This is the case if either opt-out is inactive ({@link #isOptedOut()} === false) or it is
* active and the give cookie name was found in the white-list ({@link #getWhitelistCookieNames()}).
*
* @param {String} cookieName The name of the cookie to check.
* @returns {Boolean} true if a cookie of this name may be used with respect to the opt-out status;
* false otherwise.
*/
self.maySetCookie = function(cookieName) {
return !(self.isOptedOut() && self.getWhitelistCookieNames().indexOf(cookieName) === -1);
};
return self;
}());
}));
/*************************************************************************
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2019 Adobe
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe.
**************************************************************************/
(function(factory) {
"use strict";
if (typeof module === "object" && module.exports) {
module.exports = factory();
} else {
var g = window.Granite = window.Granite || {};
g.Toggles = factory();
}
}(function() {
"use strict";
var toggles = null;
/**
* Requests toggle status from the toggle router servlet.
*
* To use it, call Granite.Toggles.isEnabled("toggle-name") e.g. on document ready:
*
* Granite.$(document).ready(function() {
* Granite.Toggles.isEnabled("sprint7-ft21");
* });
*
*/
return {
isEnabled: function(toggleName) {
toggles = toggles || fetchToggles();
return (toggles || { enabled: [] }).enabled.includes(toggleName);
function fetchToggles() {
var request = new XMLHttpRequest();
request.open("GET", Granite.HTTP.externalize("/etc.clientlibs/toggles.json"), false);
request.send(null);
if (request.status === 200) {
return JSON.parse(request.responseText);
} else {
return null;
}
}
}
};
}));
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
//------------------------------------------------------------------------------
// Initialize the Granite utils library
Granite.OptOutUtil.init(window.GraniteOptOutConfig);
Granite.HTTP.detectContextPath();
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/* global G_IS_HOOKED:false */
(function($, window) {
"use strict";
var http;
window.Granite = window.Granite || {};
window.Granite.$ = window.Granite.$ || $;
// for deprecated "shared" support (GRANITE-1602)
window._g = window._g || {};
window._g.$ = window._g.$ || $;
http = Granite.HTTP;
// necessary global modifications for ajax calls
$.ajaxSetup({
externalize: true,
encodePath: true,
hook: true,
beforeSend: function(jqXHR, s) {
// s: settings provided by the ajax call or default values
if (typeof G_IS_HOOKED === "undefined" || !G_IS_HOOKED(s.url)) {
if (s.externalize) {
s.url = http.externalize(s.url);
}
if (s.encodePath) {
s.url = http.encodePathOfURI(s.url);
}
}
if (s.hook) {
// portlet XHR hook
var hook = http.getXhrHook(s.url, s.type, s.data);
if (hook) {
s.url = hook.url;
if (hook.params) {
if (s.type.toUpperCase() === "GET") {
s.url += "?" + $.param(hook.params);
} else {
s.data = $.param(hook.params);
}
}
}
}
},
statusCode: {
403: function(jqXHR) {
if (jqXHR.getResponseHeader("X-Reason") === "Authentication Failed") {
http.handleLoginRedirect();
}
}
}
});
$.ajaxSettings.traditional = true;
}(jQuery, this));
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2015 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
(function(factory) {
"use strict";
// GRANITE-22281 Check for multiple initialization
if (window.Granite.csrf) {
return;
}
window.Granite.csrf = factory(window.Granite.HTTP);
}(function(http) {
"use strict";
// AdobePatentID="P5296"
function Promise() {
this._handler = [];
}
Promise.prototype = {
then: function(resolveFn, rejectFn) {
this._handler.push({ resolve: resolveFn, reject: rejectFn });
},
resolve: function() {
this._execute("resolve", arguments);
},
reject: function() {
this._execute("reject", arguments);
},
_execute: function(result, args) {
if (this._handler === null) {
throw new Error("Promise already completed.");
}
for (var i = 0, ln = this._handler.length; i < ln; i++) {
this._handler[i][result].apply(window, args);
}
this.then = function(resolveFn, rejectFn) {
(result === "resolve" ? resolveFn : rejectFn).apply(window, args);
};
this._handler = null;
}
};
function verifySameOrigin(url) {
// url could be relative or scheme relative or absolute
// host + port
var host = document.location.host;
var protocol = document.location.protocol;
var relativeOrigin = "//" + host;
var origin = protocol + relativeOrigin;
// Allow absolute or scheme relative URLs to same origin
return (url === origin || url.slice(0, origin.length + 1) === origin + "/") ||
(url === relativeOrigin || url.slice(0, relativeOrigin.length + 1) === relativeOrigin + "/") ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
var FIELD_NAME = ":cq_csrf_token";
var HEADER_NAME = "CSRF-Token";
var TOKEN_SERVLET = http.externalize("/libs/granite/csrf/token.json");
var promise;
var globalToken;
function logFailRequest(error) {
if (window.console) {
// eslint-disable-next-line no-console
console.warn("CSRF data not available;" +
"The data may be unavailable by design, such as during non-authenticated requests: " + error);
}
}
function getToken() {
var localPromise = new Promise();
promise = localPromise;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
try {
var data = JSON.parse(xhr.responseText);
globalToken = data.token;
localPromise.resolve(globalToken);
} catch (ex) {
logFailRequest(ex);
localPromise.reject(xhr.responseText);
}
}
};
xhr.open("GET", TOKEN_SERVLET, true);
xhr.send();
return localPromise;
}
function getTokenSync() {
var xhr = new XMLHttpRequest();
xhr.open("GET", TOKEN_SERVLET, false);
xhr.send();
try {
return globalToken = JSON.parse(xhr.responseText).token;
} catch (ex) {
logFailRequest(ex);
}
}
function clearToken() {
globalToken = undefined;
getToken();
}
function addField(form) {
var action = form.getAttribute("action");
if (form.method.toUpperCase() === "GET" || (action && !verifySameOrigin(action))) {
return;
}
if (!globalToken) {
getTokenSync();
}
if (!globalToken) {
return;
}
var input = form.querySelector('input[name="' + FIELD_NAME + '"]');
if (!input) {
input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("name", FIELD_NAME);
form.appendChild(input);
}
input.setAttribute("value", globalToken);
}
function handleForm(document) {
var handler = function(ev) {
var t = ev.target;
if (t.nodeName === "FORM") {
addField(t);
}
};
if (document.addEventListener) {
document.addEventListener("submit", handler, true);
} else if (document.attachEvent) {
document.attachEvent("submit", handler);
}
}
handleForm(document);
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async) {
if (method.toLowerCase() !== "get" && verifySameOrigin(url)) {
this._csrf = true;
this._async = async;
}
return open.apply(this, arguments);
};
var send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
if (!this._csrf) {
send.apply(this, arguments);
return;
}
if (globalToken) {
this.setRequestHeader(HEADER_NAME, globalToken);
send.apply(this, arguments);
return;
}
if (this._async === false) {
getTokenSync();
if (globalToken) {
this.setRequestHeader(HEADER_NAME, globalToken);
}
send.apply(this, arguments);
return;
}
var self = this;
var args = Array.prototype.slice.call(arguments);
promise.then(function(token) {
self.setRequestHeader(HEADER_NAME, token);
send.apply(self, args);
}, function() {
send.apply(self, args);
});
};
var submit = HTMLFormElement.prototype.submit;
HTMLFormElement.prototype.submit = function() {
addField(this);
return submit.apply(this, arguments);
};
if (window.Node) {
var ac = Node.prototype.appendChild;
Node.prototype.appendChild = function() {
var result = ac.apply(this, arguments);
if (result.nodeName === "IFRAME") {
try {
if (result.contentWindow && !result._csrf) {
result._csrf = true;
handleForm(result.contentWindow.document);
}
} catch (ex) {
if (result.src && result.src.length && verifySameOrigin(result.src)) {
if (window.console) {
// eslint-disable-next-line no-console
console.error("Unable to attach CSRF token to an iframe element on the same origin");
}
}
// Potential error: Access is Denied
// we can safely ignore CORS security errors here
// because we do not want to expose the csrf anyways to another domain
}
}
return result;
};
}
// refreshing csrf token periodically
getToken();
setInterval(function() {
getToken();
}, 300000);
return {
initialised: false,
refreshToken: getToken,
_clearToken: clearToken
};
}));
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/**
* The _g library contains all Granite component classes and utilities.
* @static
* @granite-class _g
*/
window._g = window._g || {};
// namespace
_g.shared = {};
// debug console
if (window.console === undefined) {
window.console = {log:function(m){}};
}
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/**
* A helper class providing a set of HTTP-related utilities.
* @static
* @singleton
* @class CQ.shared.HTTP
* @deprecated use Granite.HTTP and Granite.$#ajax instead
*/
_g.shared.HTTP = new function() {
/**
* Creates an empty response object.
* @private
* @static
* @return {Object} The response object
*/
var createResponse = function() {
var response = new Object();
response.headers = new Object();
response.body = new Object();
return response;
};
var getResponseFromXhr = function(request) {
if (!request) return null;
var response = createResponse();
response.body = request.responseText;
response.headers[_g.HTTP.HEADER_STATUS] = request.status;
// set properties for backward compatibility (pre 5.3)
response.responseText = request.responseText;
response.status = request.status;
return response;
};
return {
/**
* The extension for HTML files.
* @static
* @final
* @type String
*/
EXTENSION_HTML: ".html",
/**
* The extension for JSON files.
* @static
* @final
* @type String
*/
EXTENSION_JSON: ".json",
/**
* The extension for resources.
* @private
* @static
* @final
* @type String
*/
EXTENSION_RES: ".res",
/**
* The Status header.
* @static
* @final
* @type String
*/
HEADER_STATUS: "Status",
/**
* The Message header.
* @static
* @final
* @type String
*/
HEADER_MESSAGE: "Message",
/**
* The Location header.
* @static
* @final
* @type String
*/
HEADER_LOCATION: "Location",
/**
* The Path header.
* @static
* @final
* @type String
*/
HEADER_PATH: "Path",
/**
* The parameter name for no caching.
* @static
* @final
* @type String
*/
PARAM_NO_CACHE: "cq_ck",
/**
* Requests the specified URL from the server using GET. The request
* will be synchronous, unless a callback function is specified.
* @static
* @param {String} url The URL to request
* @param {Function} callback (optional) The callback function which is
* called regardless of success or failure and is passed the following
* parameters:{ headers: { "Status": 200, ... } }
* See constants above for all supported headers.
* @static
* @param {String} url The URL to request
* @param {Function} callback (optional) The callback function which is
* called regardless of success or failure and is passed the following
* parameters:Examples:
/x/y.sel.html?param=abc => /x/y
*
http://www.day.com/foo/bar.html => /foo/bar
* @static
* @param {String} url The URL, may be empty. If empty window.location.href is taken.
* @return {String} The path
* @since 5.3
*/
getPath: Granite.HTTP.getPath,
/**
* Returns the current request suffix as provided by CQURLInfo.suffix.
*
* @static
* @return {String} The suffix
*
* @since 5.5
*/
getSuffix: function() {
if (window.CQURLInfo && CQURLInfo.suffix) {
return CQURLInfo.suffix;
}
return null;
},
/**
* Returns an array with the selectors present in the given url.
* If no selectors are present, an empty array is returned.
* @static
* @param {String} url The URL, optional. If no url is provided, the
* selectors as provided by CQURLInfo.selectors
* are taken, with a fallback to window.location.href.
* @return {Array} An array containing the selectors or an empty
* array if none were found.
* @since 5.4
*/
getSelectors: function(url) {
if (!url && window.CQURLInfo) {
if (CQURLInfo.selectors) {
return CQURLInfo.selectors;
}
}
var selectors = [];
url = url || window.location.href;
url = _g.HTTP.removeParameters(url);
url = _g.HTTP.removeAnchor(url);
var fragment = url.substring(url.lastIndexOf("/"));
if (fragment) {
var split = fragment.split(".");
if (split.length > 2) {
for (var i = 0; i < split.length; i++) {
// don't add node name and extension as selectors
if (i > 0 && i < split.length - 1) {
selectors.push(split[i]);
}
}
}
}
return selectors;
},
/**
* Returns the extension of an URL. This is the string
* after the last dot until the end of the url without
* any request parameters, anchors or suffix, for
* example "html".
*
* @param {String} url The URL
* @return {String} The URL extension (without the dot)
* or an empty string if no was found.
* @since 5.4
*/
getExtension: function(url) {
if (!url && window.CQURLInfo) {
if (CQURLInfo.extension) {
return CQURLInfo.extension;
}
}
url = url || window.location.href;
// strip things from the end
url = _g.HTTP.removeParameters(url);
url = _g.HTTP.removeAnchor(url);
// extension is everything after the last dot
var pos = url.lastIndexOf(".");
if (pos < 0) {
return "";
}
// do not include the dot
url = url.substring(pos + 1);
// remove suffix if present
pos = url.indexOf("/");
if (pos < 0) {
return url;
}
return url.substring(0, pos);
},
/**
* Encodes the path of the specified URL if it is not already encoded.
* Path means the part of the URL before the first question mark or
* hash sign.
* See {@link #encodePath} for details about the encoding.
* Sample:
* /x/y+z.png?path=/x/y+z >> /x/y%2Bz.png?path=x/y+z
* Note that the sample would not work because the "+" in the request
* parameter would be interpreted as a space. Parameters must be encoded
* separately.
* @param {String} url The URL to encoded
* @return {String} The encoded URL
* @since 5.3
*/
encodePathOfURI: Granite.HTTP.encodePathOfURI,
/**
* Encodes the specified path using encodeURI. Additionally +,
* # and ? are encoded.
* The following characters are not encoded:
* 0-9 a-z A-Z
* - _ . ! ~ * ( )
* / : @ & =
* @param {String} path The path to encode
* @return {String} The encoded path
* @since 5.3
*/
encodePath: Granite.HTTP.encodePath,
/**
* Evaluates and returns the body of the specified response object.
* Alternatively, a URL can be specified, in which case it will be
* requested using a synchornous {@link #get} in order to acquire
* the response object.
* @static
* @param {Object/String} response The response object or URL
* @return {Object} The evaluated response body
* @since 5.3
*/
eval: Granite.HTTP.eval,
/**
* Checks whether the specified status code is OK.
* @static
* @param {Number} status The status code
* @return {Boolean} True if the status is OK, else false
*/
isOkStatus: function(status) {
try {
return (new String(status).indexOf("2") == 0);
} catch (e) {
return false;
}
},
/**
* Checks if the specified response is OK.
* The response object is expected to look like this:
*
{ headers: { "Status": 200, ... } }
* See constants above for all supported headers.
* @static
* @param {Object} response The response object
* @return {Boolean} True if the response is OK, else false
*/
isOk: function(response) {
try {
return _g.HTTP.isOkStatus(
response.headers[_g.HTTP.HEADER_STATUS]);
} catch (e) {
return false;
}
},
/**
* Returns if the specified response is of status 403/forbidden. If the
* status is 403 and suppressLogin is undefined the document
* is redirected to the login page.
The status is expected to be found in the "status" property of the
* response: { "status": 403 }
true to not redirect to the login page
* @return {Boolean} true if the status is 403
*/
handleForbidden: function(response, suppressLogin) {
try {
if (response[_g.HTTP.HEADER_STATUS.toLowerCase()] == 403) {
Granite.HTTP.handleLoginRedirect();
return true;
}
return false;
} catch (e) {
return false;
}
},
/**
* Gets the XHR hooked URL if called in a portlet context
* @param {String} url The URL to get
* @param {String} method The method to use to retrieve the XHR hooked URL
* @param {Object} params The parameters
* @return {String} The XHR hooked URL if available, the provided URL otherwise
*/
getXhrHook: Granite.HTTP.getXhrHook,
/**
* Gets the XHR hooked URL if called in a portlet context
* @param {String} url The URL to get
* @param {String} method The method to use to retrieve the XHR hooked URL
* @param {Object} params The parameters
* @return {String} The XHR hooked URL if available, the provided URL otherwise
*/
getXhrHookedURL: function(url, method, params) {
var hook = _g.HTTP.getXhrHook(url, method, params);
if (hook) {
return hook.url;
}
return url;
},
/**
* Reloads the XHR hook (portlet context)
* @static
* @param {String} url The URL
* @return {String} Updated URL if reload hook function exists
*/
reloadHook: function(url) {
if (typeof G_RELOAD_HOOK != "undefined" && _g.$.isFunction(G_RELOAD_HOOK)) {
if (CQURLInfo.selectorString != "") {
url = _g.HTTP.addSelector(url, CQURLInfo.selectorString);
}
url = G_RELOAD_HOOK(url) || url;
}
return url;
}
}
};
// shortcut
_g.HTTP = _g.shared.HTTP;
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/**
* A helper class providing a set of general utilities.
* @static
* @singleton
* @class CQ.shared.Util
* @granite-class _g.Util
* @deprecated
*/
_g.shared.Util = new function() {
return {
/**
* Reloads the window or replaces its location with the specified URL.
* If no window is specified, the current window will be used.
* @static
* @param {Window} win (optional) The window to reload
* @param {String} url (optional) The URL
* @param {String} preventHistory (optional) Prevent history
*/
reload: function(win, url, preventHistory) {
if (!win) win = window;
if (!url) {
url = _g.HTTP.noCaching(win.location.href);
}
url = _g.HTTP.reloadHook(url);
if (preventHistory) {
win.location.replace(url);
} else {
win.location.href = url;
}
},
/**
* Loads the specified URL in the current window.
* @static
* @param {String} url The URL
* @param {String} preventHistory (optional) Prevent history
*/
load: function(url, preventHistory) {
_g.Util.reload(window, url, preventHistory);
},
/**
* Opens a new window with the specified URL.
* If no window is specified, the current window will be used.
* @static
* @param {String} url The URL
* @param {Window} win (optional) The window to reload
* @param {String} name (optional) New window name
* @param {String} options (optional) New window options
* @return {Object} New window
*/
open: function(url, win, name, options) {
if (!win) win = window;
if (!url) {
return;
}
url = _g.HTTP.reloadHook(url);
if (!name) {
name = "";
}
if (!options) {
options = "";
}
return win.open(url, name, options);
},
/**
* Converts certain characters (&, <, >, and ") to their HTML character equivalents for literal display in web pages.
* @param {String} value The string to encode
* @return {String} The encoded text
*/
htmlEncode : function(value) {
return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/, and ") from their HTML character equivalents.
* @param {String} value The string to decode
* @return {String} The decoded text
*/
htmlDecode : function(value) {
return !value ? value : String(value).replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"').replace(/&/g, "&");
},
/**
* Truncates a string and add an ellipsis ('...') to the end if it exceeds the specified length
* @param {String} value The string to truncate
* @param {Number} length The maximum length to allow before truncating
* @param {Boolean} word True to try to find a common work break
* @return {String} The converted text
*/
ellipsis : function(value, length, word) {
if (value && value.length > length) {
if (word) {
var vs = value.substr(0, length - 2);
var index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'), vs.lastIndexOf(';'));
if (index == -1 || index < (length - 15)) {
return value.substr(0, length - 3) + "...";
} else {
return vs.substr(0, index) + "...";
}
} else {
return value.substr(0, length - 3) + "...";
}
}
return value;
},
/**
* Replaces occurrences of {n} in the specified text with
* the texts from the snippets.
* Example 1 (single snippet):
var text = CQ.shared.Util.patchText("{0} has signed in.", "Jack");
Result 1:
Jack has signed in.
* Example 2 (multiple snippets):
var text = "{0} {1} has signed in from {2}.";
text = CQ.shared.Util.patchText(text, ["Jack", "McFarland", "10.0.0.99"]);
Result 2:
Jack McFarland has signed in from 10.0.0.99.
* @static
* @param {String} text The text
* @param {String/String[]} snippets The text(s) replacing
* {n}
* @return {String} The patched text
*/
patchText: Granite.Util.patchText,
/**
* Evaluates and returns the response text of the specified response
* object.
* @static
* @param {Object} response The response object
* @return {Object} The evaluated object
* @deprecated Use {@link CQ.shared.HTTP#eval} instead
*/
eval: function(response) {
return _g.HTTP.eval(response);
},
/**
* Returns the top most accessible window.
* @static
* @return {Window} The top window
* @since 5.5
*/
getTopWindow: Granite.Util.getTopWindow,
/**
* Allows to define if Granite.Util is running in an iFrame and parent window is in another domain
* (and optionally define what would be the top window in that case.
* This is necessary to use {@link getTopWindow} in a iFrame on WebKit based browsers because
* {@link getTopWindow} iterates on parent windows to find the top one which triggers a security exception
* if one parent window is in a different domain. Exception cannot be caught but is not breaking the JS
* execution.
* @param {Object} topWindow (optional) The iFrame top window. Must be running on the same host to avoid
* security exception. Defaults to window.
*/
setIFrameMode: Granite.Util.setIFrameMode
}
};
// shortcut
_g.Util = _g.shared.Util;
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/**
* A helper class providing a set of Sling-related utilities.
* @static
* @singleton
* @class CQ.Sling
* @deprecated use Granite.Sling instead
*/
_g.shared.Sling = function() {
return {
/**
* The selector for infinite hierarchy depth when retrieving
* repository content.
* @static
* @final
* @type String
*/
SELECTOR_INFINITY: Granite.Sling.SELECTOR_INFINITY,
/**
* The parameter name for the used character set.
* @static
* @final
* @type String
*/
CHARSET: Granite.Sling.CHARSET,
/**
* The parameter name for the status.
* @static
* @final
* @type String
*/
STATUS: Granite.Sling.STATUS,
/**
* The parameter value for the status type "browser".
* @static
* @final
* @type String
*/
STATUS_BROWSER: Granite.Sling.STATUS_BROWSER,
/**
* The parameter name for the operation.
* @static
* @final
* @type String
*/
OPERATION: Granite.Sling.OPERATION,
/**
* The parameter value for the delete operation.
* @static
* @final
* @type String
*/
OPERATION_DELETE: Granite.Sling.OPERATION_DELETE,
/**
* The parameter value for the move operation.
* @static
* @final
* @type String
*/
OPERATION_MOVE: Granite.Sling.OPERATION_MOVE,
/**
* The parameter name suffix for deleting.
* @static
* @final
* @type String
*/
DELETE_SUFFIX: Granite.Sling.DELETE_SUFFIX,
/**
* The parameter name suffix for setting a type hint.
* @static
* @final
* @type String
*/
TYPEHINT_SUFFIX: Granite.Sling.TYPEHINT_SUFFIX,
/**
* The parameter name suffix for copying.
* @static
* @final
* @type String
*/
COPY_SUFFIX: Granite.Sling.COPY_SUFFIX,
/**
* The parameter name suffix for moving.
* @static
* @final
* @type String
*/
MOVE_SUFFIX: Granite.Sling.MOVE_SUFFIX,
/**
* The parameter name for the ordering.
* @static
* @final
* @type String
*/
ORDER: Granite.Sling.ORDER,
/**
* The parameter name for the replace flag.
* @static
* @final
* @type String
*/
REPLACE: Granite.Sling.REPLACE,
/**
* The parameter name for the destination flag.
* @static
* @final
* @type String
*/
DESTINATION: Granite.Sling.DESTINATION,
/**
* The parameter name for the save parameter prefix.
* @static
* @final
* @type String
*/
SAVE_PARAM_PREFIX: Granite.Sling.SAVE_PARAM_PREFIX,
/**
* The parameter name for input fields that should
* be ignored by Sling.
* @static
* @final
* @type String
*/
IGNORE_PARAM: Granite.Sling.IGNORE_PARAM,
/**
* The parameter name for login requests.
* @static
* @final
* @type String
*/
REQUEST_LOGIN_PARAM: Granite.Sling.REQUEST_LOGIN_PARAM,
/**
* Login URL
* @static
* @final
* @type String
*/
LOGIN_URL: Granite.Sling.LOGIN_URL,
/**
* Logout URL
* @static
* @final
* @type String
*/
LOGOUT_URL: Granite.Sling.LOGOUT_URL,
/**
* Detects and processes binary repository data returned by Sling
* and does some preparsing on it for more easy data handling.
* @static
* @param {Object} value The repository data to check
* @return {Object} The processed repository data
*/
processBinaryData: function(value) {
if (value && value[":jcr:data"] != undefined) {
// value is a binary
var o = new Object();
o.size = value[":jcr:data"];
o.type = value["jcr:mimeType"];
o.date = value["jcr:lastModified"];
value = o;
}
return value;
},
/**
* Returns the content path for the data.
* @static
* @param {String} relPath The relative path to resolve
* @param {String} absPath The absolute path to resovle against
* @param {Boolean} allowParentPaths Indicates parent paths (../) should be processed at the start of the
* relative path
* @return {String} The absolute path path
*/
getContentPath: function(relPath, absPath, allowParentPaths) {
var path = absPath;
if (path.lastIndexOf(".") > path.lastIndexOf("/")) {
// remove selectors and extension from absPath:
// /content/foo.bar.html >> /content/foo
path = path.substr(0, path.indexOf(".", path.lastIndexOf("/")));
}
if (relPath) {
if (relPath.indexOf("/") == 0) {
path = relPath;
} else {
if (allowParentPaths) {
while (relPath.indexOf("../") == 0) {
relPath = relPath.substring(3);
path = path.substring(0, path.lastIndexOf("/"));
}
}
relPath = relPath.replace("./", "");
path = path + "/" + relPath;
}
}
return path;
}
};
}();
// shortcut
_g.Sling = _g.shared.Sling;
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/**
* Provides static utilities for XSS management.
* @static
* @singleton
* @since 5.4
* @class CQ.shared.XSS
* @granite-class _g.XSS
* @deprecated
*/
_g.shared.XSS = new function() {
return {
/**
* Get XSS property name from a provided property name
*
* @static
* @param {String} propertyName Property name
* @return {String} XSS property name
*/
getXSSPropertyName: function(propertyName) {
if (!propertyName) {
return '';
}
if (_g.XSS.KEY_REGEXP.test(propertyName)) {
return propertyName;
}
return propertyName += _g.XSS.KEY_SUFFIX;
},
/**
* Get XSS property value from provided property name and json record
*
* @static
* @param {Object} rec Object containing the properties and their values
* @param {String} propertyName Property name
* @param {Number} ellipsisLimit Maximum number of characters
* @return {String} XSS property value
*/
getXSSRecordPropertyValue: function(rec, propertyName, ellipsisLimit) {
var value = '';
if (rec && propertyName) {
var xssPropValue = rec.get(this.getXSSPropertyName(propertyName));
if (xssPropValue) {
value = xssPropValue;
} else {
value = this.getXSSValue(rec.get(propertyName));
}
if (ellipsisLimit && !isNaN(ellipsisLimit)) {
value = _g.Util.ellipsis(value, ellipsisLimit, true);
}
}
return value;
},
/**
* Get XSS property value from provided property name and table
*
* @static
* @param {Object} table Object containing the properties and their values
* @param {String} propertyName Property name
* @param {Number} ellipsisLimit Maximum number of characters
* @return {String} XSS property value
*/
getXSSTablePropertyValue: function(table, propertyName, ellipsisLimit) {
var value = '';
if (table && propertyName) {
var xssPropValue = table[this.getXSSPropertyName(propertyName)];
if (xssPropValue) {
value = xssPropValue;
} else {
value = this.getXSSValue(table[propertyName]);
}
if (ellipsisLimit && !isNaN(ellipsisLimit)) {
value = _g.Util.ellipsis(value, ellipsisLimit, true);
}
}
return value;
},
/**
* XSS value renderer
*
* @static
* @param {String} val Value to protect
* @return {String} XSS protected value
*/
getXSSValue: function(val) {
if (val) {
// There is a value to display, which we encode
return _g.Util.htmlEncode(val);
} else {
// There was no value to display
return '';
}
},
/**
* Update configuration object's property name if XSS is enabled for it
*
* @static
* @param {Object} cfg Configuration object
* @param {String} propertyName Property name of the provided configuration object
*/
updatePropertyName: function(cfg, propertyName) {
if (!cfg || !propertyName || !cfg[propertyName]) {
return;
}
if (cfg['xssProtect'] && !cfg['xssKeepPropName']) {
cfg[propertyName] = this.getXSSPropertyName(cfg[propertyName]);
}
},
/**
* XSS property renderer
*
* @static
* @param {String} val Value to display if XSS would not have been requested or is not available
* @param {Object} meta Field metadata
* @param {Object} cfg Field configuration
* @param {Object} rec Record containing information
* @return {String} XSS property value
*/
xssPropertyRenderer: function(val, meta, rec, cfg) {
if (cfg && cfg['dataIndex'] && rec && rec.data && rec.data[this.getXSSPropertyName(cfg['dataIndex'])]) {
// The record contains the XSS property equivalent
val = rec.data[this.getXSSPropertyName(cfg['dataIndex'])];
if (cfg['ellipsisLimit'] && !isNaN(cfg['ellipsisLimit'])) {
val = _g.Util.ellipsis(val, cfg['ellipsisLimit'], true);
}
return val;
} else if (val) {
// The record does not contain the XSS property equivalent
return val;
} else {
// There was no value to display
return '';
}
}
}
};
// shortcut
_g.XSS = _g.shared.XSS;
/**
* Key suffix for XSS property name
* @static
* @final
* @type String
*/
_g.XSS.KEY_SUFFIX = "_xss";
/**
* Key regular expression to test if a property name already ends with XSS suffix
* @private
* @static
* @final
* @type Object
*/
_g.XSS.KEY_REGEXP = new RegExp(_g.XSS.KEY_SUFFIX + "$");
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/**
* A helper class providing a set of utilities related to internationalization
* (i18n). Note: for cq localization, make sure to use CQ.I18n.get().
* @static
* @singleton
* @class CQ.I18n
* @granite-class _g.I18n
* @deprecated use Granite.I18n instead
*/
_g.shared.I18n = Granite.I18n;//function() {
// shortcut
_g.I18n = _g.shared.I18n;
_g.shared.I18n.getMessage = Granite.I18n.get;
_g.shared.I18n.getVarMessage = Granite.I18n.getVar;
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/**
* A helper class providing a set of String related utilities.
* @static
* @singleton
* @since 5.5
* @class CQ.shared.String
* @granite-class _g.String
* @deprecated
*/
_g.shared.String = new function() {
return {
/**
* Check to see if the the str starts with the prefix.
* The comparison is case sensitive.
* @static
* @param {String} str The string to check.
* @param {String} prefix The prefix to find.
* @return {Boolean} if the str starts with the prefix
* return true, otherwise false.
*/
startsWith: function( str, prefix ) {
if (str == null || prefix == null) {
return str == null && prefix == null;
}
if (prefix.length > str.length) {
return false;
}
// ensure we are dealing with the string form of this object
var sMatch = str.toString();
var sSearch = prefix.toString();
return (sMatch.indexOf(sSearch) == 0);
},
/**
* Check to see if the the str ends with the suffix.
* The comparison is case sensitive.
* @static
* @param {String} str The string to check.
* @param {String} suffix The suffix to find.
* @return {Boolean} if the str ends with the suffix
* return true, otherwise false.
*/
endsWith: function( str, suffix ) {
if (str == null || suffix == null) {
return str == null && suffix == null;
}
if (suffix.length > str.length) {
return false;
}
// ensure we are dealing with the string form of this object
str = str.toString();
suffix = suffix.toString();
return (str.lastIndexOf(suffix) == (str.length - suffix.length));
},
/**
* Check to see if the the str contains the searchStr.
* The comparison is case sensitive.
* @static
* @param {String} str The string to check.
* @param {String} searchStr The prefix to find.
* @return {Boolean} if the str ends with the suffix
* return true, otherwise false.
*/
contains: function( str, searchStr ) {
if (str == null || searchStr == null) {
return false;
}
// ensure we are dealing with the string form of this object
str = str.toString();
searchStr = searchStr.toString();
return (str.indexOf(searchStr) >= 0);
}
}
};
// shortcut
_g.String = _g.shared.String;
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
/**
* @class _g.shared.ClientSidePersistence
* The _g.shared.ClientSidePersistence is a class providing method to persist a map of pairs (key/value).
* @constructor
* Creates a new ClientSidePersistence object.
*/
_g.shared.ClientSidePersistence = function(cfg) {
var session = {
/**
* @cfg {String} PERSISTENCE_NAME
* Persistence global key name
* @final
* @private
*/
PERSISTENCE_NAME: _g.shared.ClientSidePersistence.decoratePersistenceName("ClientSidePersistence"),
/**
* @cfg {Object} config
* Default configuration of ClientSidePersistence
*/
config: {},
/**
* @property {Object} cache
* Client side persistence cache object
* @private
*/
cache: null,
/**
* Returns current ClientSidePersistence mode
* @return {Object} Current ClientSidePersistence mode (see {@link #config})
*/
getMode: function() {
return this.config.mode;
},
/**
* Returns window object used by ClientSidePersistence
* @return {Object} window object used by ClientSidePersistence
*/
getWindow: function() {
return this.config['window'] || _g.shared.Util.getTopWindow();
},
/**
* Prints actual ClientSidePersistence content restricted to specified container name (if specified) and to used mode
* @private
* @return
*/
debug: function() {
if (console) {
var map = this.getMap();
var debugInfo = "[ClientSidePersistence -> mode=" + this.getMode().name + ", container=" + (this.config.container || '') + "]\n";
var count = 0;
var containerRE = new RegExp('^' + this.config.container + '/');
for (var idx = 0, keys = Object.keys(map).sort(), last = null; idx < keys.length; idx++) {
var key = keys[idx];
if (this.config.container && (typeof(key) == 'string') && !key.match(containerRE)) {
continue;
}
var value = map[key];
debugInfo += "-[" + ++count + "]-> '" + key.replace(containerRE, '') + "' = '" + decodeURIComponent(value) + "'\n";
}
if (!count) {
debugInfo += "(container is empty)";
}
console.log(debugInfo);
}
},
/**
* Returns user provided key with container name (if it's specified)
* @param {String} key
* @private
* @return {String} user provided key with container name
*/
keyName: function(key) {
return (this.config.container ? (this.config.container + '/') : '') + key;
},
/**
* Returns the list of all the keys contained into the persistence
* @return {String[]} list of the keys
*/
getKeys: function() {
var map = this.getMap();
var keys = [];
if( map ) {
for ( var k in map ) {
if ( this.config.container ) {
if (k.indexOf(this.config.container + '/') == 0 ) {
var key = k.substring( this.config.container.length + 1 );
keys.push(key);
}
} else {
keys.push(k);
}
}
}
return keys;
},
/**
* Returns the value of the given key.
* @param {String} key
* @return {String} value of a given key
*/
get: function(key) {
var value = this.getMap()[this.keyName(key)];
return value ? decodeURIComponent(value) : value;
},
/**
* Sets the value of the given key.
* @param {String} key
* @param {String} value
*/
set: function(key, value) {
key = (typeof key === 'string') ? key.replace(/:=/g, '') : '';
var eventData = {'key' : key};
key = this.keyName(key);
if (!key.length) {
return;
}
var result = [];
var map = this.getMap();
eventData.action = map[key] ? "update": "set";
if (value) {
map[key] = encodeURIComponent(value);
} else {
eventData.action = "remove";
delete map[key];
}
for (var entry in map) {
result.push(entry + ':=' + map[entry]);
}
this.cache = map;
this.write(result.join('|'));
_g.$.extend(eventData, {
'value': value,
'mode': this.getMode().name,
'container': this.config.container
});
_g.$(_g.shared.ClientSidePersistence).trigger(_g.shared.ClientSidePersistence.EVENT_NAME, eventData);
},
/**
* Returns object containing a map of key/value pairs
* @private
* @return {Object} map of key/value pairs
*/
getMap: function() {
if (!this.cache || !this.config.useCache) {
var data = this.read().split('|');
var result = {};
for (var idx = 0; idx < data.length; idx++) {
var chunks = data[idx].split(':=');
var key = chunks[0];
if (key && key.length) {
result[key] = chunks[1] || '';
}
}
this.cache = result;
}
return this.cache;
},
/**
* Removes key from the persistence
* @param {String} key
* @return
*/
remove: function(key) {
this.set(key);
},
/**
* Clears the whole content of persistence object
* @return
*/
clearMap: function() {
this.write();
},
/**
* Reads the whole content of persistence object
* @private
* @return {String} content of persistence object
*/
read: function() {
return this.config.mode.read(this) || '';
},
/**
* Stores user provided data in persistence object
* @param {String} data
* @private
* @return
*/
write: function(data) {
this.config.mode.write(this, data || '');
}
};
/* applies user provided config on top of default configuration */
_g.$.extend(session.config, _g.shared.ClientSidePersistence.getDefaultConfig(), cfg);
if (session.config.useContainer === false) {
session.config.container = null;
}
/* check if sessionStorage is supported and switch to localStorage otherwise */
var useFallback;
var testItem = 'test-' + Math.random();
if (session.config.mode === _g.shared.ClientSidePersistence.MODE_SESSION) {
useFallback = false;
try {
window.sessionStorage.setItem(testItem, testItem);
window.sessionStorage.removeItem(testItem);
} catch (error) {
useFallback = true;
}
if (useFallback) {
session.config.mode = _g.shared.ClientSidePersistence.MODE_LOCAL;
}
}
/* check if localStorage is supported and switch to window.name otherwise */
if (session.config.mode === _g.shared.ClientSidePersistence.MODE_LOCAL) {
useFallback = false;
try {
window.localStorage.setItem(testItem, testItem);
window.localStorage.removeItem(testItem);
} catch (error) {
useFallback = true;
}
if (useFallback) {
session.config.mode = _g.shared.ClientSidePersistence.MODE_WINDOW;
}
}
return session;
};
/**
* @cfg {String} EVENT_NAME
* Event name triggered while setting/updating key in ClientSidePersistence
* @final
* @private
*/
_g.shared.ClientSidePersistence.EVENT_NAME = 'ClientSidePersistence';
/**
* window.sessionStorage implementation for ClientSidePersistence
*/
_g.shared.ClientSidePersistence.MODE_SESSION = {
/**
* @property {String} name
* Name of MODE_SESSION storage implementation
*/
name: 'session',
/**
* Reads the whole content of persistence object (using window.sessionStorage)
* @param {ClientSidePersistence} self
* @return content of persistence object
*/
read: function(self) {
return self.getWindow().sessionStorage.getItem(self.PERSISTENCE_NAME);
},
/**
* Stores user provided data in persistence object (using window.sessionStorage)
* @param {ClientSidePersistence} self
* @param {String} value
* @return
*/
write: function(self, value) {
if (Granite.OptOutUtil.isOptedOut()) return;
try {
self.getWindow().sessionStorage.setItem(self.PERSISTENCE_NAME, value);
} catch(error) {
//could not deal with the setItem
return;
}
}
};
/**
* window.localStorage implementation for ClientSidePersistence
*/
_g.shared.ClientSidePersistence.MODE_LOCAL = {
/**
* @property {String} name
* Name of MODE_LOCAL storage implementation
*/
name: 'local',
/**
* Reads the whole content of persistence object (using window.localStorage)
* @param {ClientSidePersistence} self
* @return content of persistence object
*/
read: function(self) {
return self.getWindow().localStorage.getItem(self.PERSISTENCE_NAME);
},
/**
* Stores user provided data in persistence object (using window.localStorage)
* @param {ClientSidePersistence} self
* @param {String} value
* @return
*/
write: function(self, value) {
if (Granite.OptOutUtil.isOptedOut()) return;
try {
self.getWindow().localStorage.setItem(self.PERSISTENCE_NAME, value);
} catch(error) {
//could not deal with the setItem
return;
}
}
};
_g.shared.ClientSidePersistence.decoratePersistenceName = function(name) {
return name;
};
/**
* window.name implementation for ClientSidePersistence
*/
_g.shared.ClientSidePersistence.MODE_WINDOW = {
/**
* @property {String} name
* Name of MODE_WINDOW storage implementation
*/
'name': 'window',
/**
* Reads the whole content of persistence object (using window.name)
* @param {ClientSidePersistence} self
* @return content of persistence object
*/
read: function(self) {
return self.getWindow().name;
},
/**
* Stores user provided data in persistence object (using window.name)
* @param {ClientSidePersistence} self
* @param {String} value
* @return
*/
write: function(self, value) {
if (Granite.OptOutUtil.isOptedOut()) return;
self.getWindow().name = value;
}
};
/**
* document.cookie implementation for ClientSidePersistence
*/
_g.shared.ClientSidePersistence.MODE_COOKIE = {
/**
* @property {String} COOKIE_NAME
* Cookie key name used by MODE_COOKIE persistence mode
*/
COOKIE_NAME: _g.shared.ClientSidePersistence.decoratePersistenceName("SessionPersistence"),
/**
* @property {String} name
* Name of MODE_COOKIE storage implementation
*/
name: 'cookie',
/**
* Reads the whole content of persistence object (using document.cookie)
* @param {ClientSidePersistence} self
* @return content of persistence object
*/
read: function(self) {
return _g.shared.ClientSidePersistence.CookieHelper.read(this.COOKIE_NAME);
},
/**
* Stores or clears user provided data in persistence object (using document.cookie)
* @param {ClientSidePersistence} self
* @param {String} value (optional)
* @return
*/
write: function(self, value) {
if (Granite.OptOutUtil.isOptedOut() && !Granite.OptOutUtil.maySetCookie(this.COOKIE_NAME)) return;
if (!value) {
_g.shared.ClientSidePersistence.CookieHelper.erase(this.COOKIE_NAME);
} else {
_g.shared.ClientSidePersistence.CookieHelper.set(this.COOKIE_NAME, value, 365 /* days */);
}
}
};
/*
* ClientSidePersistence default config
*/
_g.shared.ClientSidePersistence.getDefaultConfig = function() {
return {
/**
* @property {Object} window
* Defines which window object should be used by ClientSidePersistence
*/
window: _g.shared.Util.getTopWindow(),
/**
* @property {Boolean} useCache
* Determines if ClientSidePersistence should use internal cache
*/
useCache: false,
/**
* @property {String} container
* Container name where key/values will be stored (by default it's null)
*/
container: null,
/**
* @property {Object} mode
* Defines which mode should be used (available modes are {@link _g.shared.ClientSidePersistence.MODE_SESSION MODE_SESSION},
* {@link _g.shared.ClientSidePersistence.MODE_LOCAL MODE_LOCAL}, {@link _g.shared.ClientSidePersistence.MODE_WINDOW MODE_WINDOW}
* and {@link _g.shared.ClientSidePersistence.MODE_COOKIE MODE_COOKIE})
*/
mode: _g.shared.ClientSidePersistence.MODE_LOCAL
};
};
/**
* Cookie helper class.
* @class _g.shared.ClientSidePersistence.CookieHelper
* @singleton
*/
_g.shared.ClientSidePersistence.CookieHelper = {
/**
* Sets a cookie.
* @param {String} name
* @param {String} value
* @param {Number} days
*/
set: function(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toGMTString();
}
if (value) {
value = encodeURIComponent(value);
}
document.cookie = name + "=" + value + expires + "; path=/";
},
/**
* Returns the value of the cookie of the given name.
* @param {String} name
* @return {String} value of a given name (can be null)
*/
read: function(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) {
var value = c.substring(nameEQ.length, c.length);
return value ? decodeURIComponent(value) : null;
}
}
return null;
},
/**
* Removes the cookie of the given name.
* @param {String} name
*/
erase: function(name) {
_g.shared.ClientSidePersistence.CookieHelper.set(name, "", -1);
}
};
/*
* Clears client side persistence using all implemented modes
*/
_g.shared.ClientSidePersistence.clearAllMaps = function() {
var modes = [
_g.shared.ClientSidePersistence.MODE_COOKIE,
_g.shared.ClientSidePersistence.MODE_LOCAL,
_g.shared.ClientSidePersistence.MODE_SESSION,
_g.shared.ClientSidePersistence.MODE_WINDOW
];
_g.$.each(modes, function(id, mode) {
var persistence = new _g.shared.ClientSidePersistence({'mode': mode});
persistence.clearMap();
});
};
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
//------------------------------------------------------------------------------
// Initialize the Granite shared library
//todo: user language (not yet available)
//_g.I18n.init({locale: _g.User.getLanguage()});
_g.I18n.init();
(()=>{"use strict";window.$CQ="u"